home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2007 September / PCWSEP07.iso / Software / Linux / Linux Mint 3.0 Light / LinuxMint-3.0-Light.iso / casper / filesystem.squashfs / usr / sbin / update-python-modules < prev    next >
Encoding:
Text File  |  2006-11-27  |  10.3 KB  |  303 lines

  1. #! /usr/bin/python
  2. #
  3. # copyright (c) 2006 Josselin Mouette <joss@debian.org>
  4. # Licensed under the GNU Lesser General Public License, version 2.1
  5. # See COPYING for details
  6.  
  7. import sys,os,os.path
  8. from optparse import OptionParser
  9. from py_compile import compile, PyCompileError
  10.  
  11. basepath='/var/lib/python-support'
  12. sourcepath='/usr/share/python-support'
  13. extensionpath='/usr/lib/python-support'
  14.  
  15. parser = OptionParser(usage="usage: %prog [-v] [-c] package_directory [...]\n"+
  16.                 "       %prog [-v] [-c] package.dirs [...]\n"+
  17.                 "       %prog [-v] [-a|-f]")
  18.  
  19. parser.add_option("-v", "--verbose", action="store_true", dest="verbose",
  20.                   help="verbose output", default=False)
  21. parser.add_option("-c", "--clean", action="store_true", dest="clean_mode",
  22.           help="clean modules instead of compiling them",
  23.           default=False)
  24. parser.add_option("-a", "--rebuild-all", action="store_true",
  25.                   dest="rebuild_all", default=False,
  26.           help="rebuild all private modules for a new default python version")
  27. parser.add_option("-f", "--force-rebuild-all", action="store_true",
  28.                   dest="rebuild_everything", default=False,
  29.           help="rebuild all modules, including public modules for all python versions.")
  30. parser.add_option("-b", "--bytecompile", action="store_true", dest="force_private",
  31.                   help="[deprecated] byte-compilation mode: only handle private modules",
  32.                   default=False)
  33. parser.add_option("-i", "--install", action="store_true", dest="force_public",
  34.                   help="[deprecated] installation mode: only handle public modules",
  35.           default=False)
  36.  
  37. (options, args) = parser.parse_args()
  38.  
  39. if not os.path.isdir(basepath):
  40.   os.mkdir(basepath)
  41.  
  42. sys.path.append("/usr/lib/python-support/private/")
  43. import pysupport
  44. from pysupport import py_supported,py_installed,py_oldversions
  45.  
  46. def debug(x):
  47.   if(options.verbose):
  48.     print x
  49.  
  50. # I should use the sets type instead
  51. def isect(l1,l2):
  52.   return [i for i in l1 if i in l2]
  53.   
  54. def concat(l1,l2):
  55.   return l1 + [i for i in l2 if i not in l1]
  56.  
  57. versions_dict={}
  58.  
  59. def dir_versions(dir):
  60.   if dir not in versions_dict:
  61.     verfile=os.path.join(dir,'.version')
  62.     if dir.startswith(extensionpath):
  63.       # Directory in /usr/lib: only one version
  64.       vers=os.path.split(dir)[1]
  65.       if vers in py_supported:
  66.         versions_dict[dir]=[vers]
  67.       else:
  68.         versions_dict[dir]=[]
  69.     elif dir.startswith(sourcepath):
  70.       # Directory in /usr/share
  71.       extdir=dir.replace(sourcepath,extensionpath,1)
  72.       if os.path.exists(verfile):
  73.         # If we have a .version, use it
  74.         versions_dict[dir]=pysupport.version_list(file(verfile).readline())
  75.       elif os.path.isdir(extdir):
  76.         # Try to obtain the list of supported versions
  77.         # from the extensions in /usr/lib
  78.         versions_dict[dir]=isect(py_supported,os.listdir(extdir))
  79.       else:
  80.         # Otherwise, support all versions
  81.         versions_dict[dir]=py_supported
  82.     else:
  83.       raise "[Internal error] %s: unsupported path for byte-compilation."
  84.   return versions_dict[dir]
  85.  
  86. def bytecompile_only(basedir,dir,file):
  87.   if file.endswith('.py'):
  88.     fullpath=os.path.join(basedir,dir,file)
  89.     debug("compile "+fullpath+'c')
  90.     try:
  91.       # Note that compile doesn't raise PyCompileError by default
  92.       compile(fullpath, doraise=True)
  93.     except IOError, (errno, strerror):
  94.       sys.stderr.write("WARNING: I/O error while trying to byte-compile %s (%s): %s\n" % (fullpath, errno, strerror))
  95.     except PyCompileError, inst:
  96.       sys.stderr.write("WARNING: compile error while trying to byte-compile %s: %s\n" % (fullpath, inst.msg))
  97.     except:
  98.       sys.stderr.write("WARNING: unexpected error while trying to byte-compile %s: %s\n" % (fullpath, sys.exc_info()[0]))
  99.  
  100. def clean_simple(basedir,dir,file):
  101.   if file.endswith('.py'):
  102.     for ext in ['c','o']:
  103.       fullpath=os.path.join(basedir,dir,file+ext)
  104.       if os.path.exists(fullpath):
  105.         debug("remove "+fullpath)
  106.         os.remove(fullpath)
  107.  
  108. def install_modules(versions):
  109.   def install_modules_func(basedir,dir,file):
  110.     if file == '.version':
  111.       return
  112.     fullpath=os.path.join(basedir,dir,file)
  113.     for py in isect(dir_versions(basedir),versions):
  114.       destpath=os.path.join(basepath,py,dir,file)
  115.       try:
  116.         os.makedirs(os.path.join(basepath,py,dir))
  117.       except OSError:
  118.         pass
  119.       if file[-4:] not in ['.pyc','.pyo']:
  120.         debug("link "+destpath)
  121.         # os.path.exists returns False for broken symbolic links
  122.         if os.path.exists(destpath) or os.path.islink(destpath):
  123.           # Oops, the file already exists. 
  124.           # Check whether we are conflicting with something else.
  125.           for otherdir in dirs_i:
  126.             if otherdir == basedir:
  127.               continue
  128.             if os.path.exists(os.path.join(otherdir,dir,file)):
  129.               raise "Trying to overwrite %s which is already provided by %s"%(os.path.join(dir,file),otherdir)
  130.           # This is probably a case of postinst re-running. 
  131.           # Let's proceed.
  132.           debug("overwrite! "+destpath)
  133.           os.remove(destpath)
  134.         os.symlink(fullpath,destpath)
  135.       # Files are NOT byte-compiled here, this MUST be done later.
  136.   return install_modules_func
  137.  
  138. def clean_modules(basedir,dir,file):
  139.   fullpath=os.path.join(basedir,dir,file)
  140.   for py in dir_versions(basedir):
  141.     destpath=os.path.join(basepath,py,dir,file)
  142.     l=[destpath]
  143.     if file.endswith('.py'):
  144.       l+=[destpath+'c',destpath+'o']
  145.     for path in l:
  146.       if os.path.exists(path):
  147.         debug("remove "+path)
  148.         os.remove(path)
  149.     try:
  150.       os.removedirs(os.path.join(basepath,py,dir))
  151.     except OSError:
  152.       pass
  153.  
  154. def clean_modules_gen(versions):
  155.   return clean_modules
  156.  
  157. def process(basedir,func):
  158.   debug("Looking at %s..."%(basedir))
  159.   for dir, dirs, files in os.walk(basedir):
  160.     dir = dir[len(basedir):].lstrip('/')
  161.     for file in files:
  162.       func(basedir, dir, file)
  163.     for file in dirs:
  164.       if os.path.islink(os.path.join(basedir,dir,file)):
  165.         func(basedir, dir, file)
  166.  
  167. def process_extensions(basedir,func,version=None):
  168.   basedir=basedir.replace(sourcepath,extensionpath,1)
  169.   if os.path.isdir(basedir):
  170.     for vers in os.listdir(basedir):
  171.       if version and vers != version:
  172.         continue
  173.       verdir=os.path.join(basedir,vers)
  174.       if os.path.isdir(verdir):
  175.         process(verdir,func([vers]))
  176.  
  177. def dirlist_file(f):
  178.   return [ l.rstrip('\n') for l in file(f) if len(l)>1 ]
  179.  
  180. def generate_pathfile(py):
  181.   path=os.path.join(basepath,py)
  182.   if not os.path.isdir(path):
  183.     return
  184.   pathfile=os.path.join(path,".path")
  185.   debug("Generation of %s..."%pathfile)
  186.   pathlist=[path]
  187.   for f in os.listdir(path):
  188.     f=os.path.join(path,f)
  189.     if f.endswith(".pth") and os.path.isfile(f):
  190.       for l in file(f):
  191.         l=l.rstrip('\n')
  192.         pathlist.append(l)
  193.         pathlist.append(os.path.join(path,l))
  194.   fd=file(pathfile,"w")
  195.   fd.writelines([l+'\n' for l in pathlist])
  196.  
  197. def bytecompile_all(py,path=None):
  198.   if not path:
  199.     path=os.path.join(basepath,py)
  200.     generate_pathfile(py)
  201.   if not os.path.isdir(path):
  202.     return
  203.   debug("Byte-compilation of whole %s..."%path)
  204.   os.spawnl(os.P_WAIT, '/usr/bin/'+py, py,
  205.             os.path.join('/usr/lib/',py,'compileall.py'), '-q', path)
  206.  
  207. def bytecompile_privatedir(basedir):
  208.   versionfile=os.path.join(basedir,".pyversion")
  209.   if os.path.isfile(versionfile):
  210.     specific_version=file(versionfile).readline().rstrip('\n')
  211.     bytecompile_all("python"+specific_version,basedir)
  212.   else:
  213.     process(basedir,bytecompile_only)
  214.  
  215. # Parse arguments
  216. do_dirs_i=[]
  217. do_dirs_b=[]
  218. for arg in args:
  219.   if os.path.isabs(arg):
  220.     if not arg.startswith(sourcepath):
  221.       parser.error("%s is not in the python-support directory."%arg)
  222.   else:
  223.     arg=os.path.join(sourcepath,arg)
  224.   if not os.path.exists(arg):
  225.     parser.error("%s does not exist"%arg)
  226.   if arg.endswith('.dirs'):
  227.     do_dirs_b+=dirlist_file(arg)
  228.     if options.force_public:
  229.       parser.error("Option -i cannot be used with a private module .dirs file.")
  230.   elif os.path.isdir(arg):
  231.     do_dirs_i.append(arg)
  232.     if options.force_private:
  233.       parser.error("Option -b cannot be used with a public module directory.")
  234.   else:
  235.     parser.error("%s is not a directory"%arg)
  236.  
  237.  
  238. # Read full list from the source directory
  239. # directories are stuff to be installed
  240. # foo.dirs files list directories to bytecompile in place
  241. dirs_b = []
  242. dirs_i = []
  243. for f in os.listdir(sourcepath):
  244.   f=os.path.join(sourcepath,f)
  245.   if os.path.isdir(f):
  246.     dirs_i.append(f)
  247.   elif f.endswith('.dirs'):
  248.     dirs_b+=dirlist_file(f)
  249.  
  250. if options.rebuild_everything:
  251.   options.rebuild_all = True
  252.   for pyver in py_supported:
  253.     dir = os.path.join(basepath,pyver)
  254.     if os.path.isdir(dir):
  255.       os.spawnlp(os.P_WAIT, 'rm', 'rm', '-rf', dir)
  256.  
  257. # Check for changes in installed python versions
  258. for pyver in py_oldversions+py_supported:
  259.   dir = os.path.join(basepath,pyver)
  260.   # Check for ".path" because sometimes the directory already exists 
  261.   # while the python version isn't installed, because of some .so's.
  262.   if pyver in py_installed and not os.path.isfile(os.path.join(dir,".path")):
  263.     debug("Building all modules in %s..."%(dir))
  264.     for basedir in dirs_i:
  265.       process(basedir,install_modules([pyver]))
  266.       process_extensions(basedir,install_modules,pyver)
  267.     # Byte-compile after running install_modules
  268.     bytecompile_all(pyver)
  269.   if pyver not in py_installed and os.path.isdir(dir):
  270.     debug("Removing obsolete directory %s..."%(dir))
  271.     os.spawnlp(os.P_WAIT, 'rm', 'rm', '-rf', dir)
  272.  
  273. if options.rebuild_all:
  274.   for basedir in dirs_b:
  275.     process(basedir,clean_simple)
  276.     bytecompile_privatedir(basedir)
  277.  
  278.  
  279. # Now for the processing of what was handed on the command line
  280. for basedir in do_dirs_b:
  281.   if not options.clean_mode:
  282.     bytecompile_privatedir(basedir)
  283.   else:
  284.     process(basedir,clean_simple)
  285.  
  286. to_bytecompile=to_clean=[]
  287. for basedir in do_dirs_i:
  288.   if not options.clean_mode:
  289.     process(basedir,install_modules(py_installed))
  290.     process_extensions(basedir,install_modules)
  291.     to_bytecompile = concat(to_bytecompile,isect(dir_versions(basedir),py_installed))
  292.   else:
  293.     process(basedir,clean_modules)
  294.     process_extensions(basedir,clean_modules_gen)
  295.     to_clean = concat(to_clean,isect(dir_versions(basedir),py_installed))
  296. # Byte-compile after running install_modules
  297. for py in to_bytecompile:
  298.   bytecompile_all(py)
  299. # When removing a module, we have removed the .pyc but we still need
  300. # to regenerate the .path file
  301. for py in to_clean:
  302.   generate_pathfile(py)
  303.